package com.tulele.vtool.utils;

import org.apache.commons.lang3.StringUtils;
import sun.font.FontDesignMetrics;

import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import java.awt.*;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Iterator;
import java.util.UUID;

/**
 * @version : V1.0
 * @ClassName: TestCutImages
 * @Description: TODO
 * @Auther: chujiu
 * @Date: 2020/11/26
 */
public class CutImages {
    public static void main(String[] args) throws Exception {
        System.out.println("========== 开始！ ==========");
        // 图片访问文件夹路径
        String inputImgPath = "G:\\weixun\\poster\\test1126\\";
        // 图片结果文件夹路径
        String outputImgPath = "G:\\weixun\\poster\\test1126\\result\\";

        // 海报背景图片文件路径
        String bcg = inputImgPath + "poster3.png";
        // 海报头像图片文件路径
        String head = inputImgPath + "head.jpg";
        // 海报推广大图片文件路径
        String pic = inputImgPath + "pic.jpg";
        // 海报二维码图片文件路径
        String code = inputImgPath + "myQrCode.jpg";

        // 海报背景图片宽度、高度
        int bcgW = 750;
        int bcgH = 1330;

        // 海报头像图片宽度、高度、左边距离、上边距离,是否圆角
        int headW = 162;
        int headH = 162;
        int headL = 296;
        int headT = 24;
        int headR = 80;

        // 海报推广大图片宽度、高度、左边距离、上边距离
        int picW = 566;
        int picH = 408;
        int picL = 88;
        int picT = 290;

        // 海报二维码图片宽度、高度、左边距离、上边距离
        int codeW = 162;
        int codeH = 162;
        int codeL = 294;
        int codeT = 1027;

        // 海报文字
        String name = "姓名：刘潇涛";
        String phone = "电话：10086110086";
        String comp = "公司：能力有限公司";

        File bcgFile = new File(URLDecoder.decode(bcg, "utf-8"));
        File headFile = new File(URLDecoder.decode(head, "utf-8"));
        File picFile = new File(URLDecoder.decode(pic, "utf-8"));
        File codeFile = new File(URLDecoder.decode(code, "utf-8"));

        BufferedImage bcgBuffImg = ImageIO.read(bcgFile);
        BufferedImage headBuffImg = ImageIO.read(headFile);
        BufferedImage picBuffImg = ImageIO.read(picFile);
        BufferedImage codeBuffImg = ImageIO.read(codeFile);

        // 头像处理
        headBuffImg = createRoundedImage(head, headR);

        // 按照底图的宽高生成新的图片
        BufferedImage image = new BufferedImage(bcgW, bcgH, BufferedImage.TYPE_INT_RGB);
        // 开启画笔
        Graphics2D g = image.createGraphics();
        // 去毛边
        g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        // 画海报背景图片
        g.drawImage(bcgBuffImg, 0, 0, bcgW, bcgH, null);
        // 画海报头像图片
        g.drawImage(headBuffImg, headL, headT, headW, headH, null);
        // 画海报推广大图片图片
        g.drawImage(picBuffImg, picL, picT, picW, picH, null);
        // 画海报二维码图片
        g.drawImage(codeBuffImg, codeL, codeT, codeW, codeH, null);

        // 图片上写文字
        Font font = new Font("思源黑体", Font.BOLD, 28);
        g.setFont(font);
        g.setColor(new Color(0, 0, 0));

        FontDesignMetrics metrics = FontDesignMetrics.getMetrics(font);
        int width = getWordWidth(font, comp);// 计算文字的宽
        int height = metrics.getHeight();// 计算高，计算使用字体的最大的高度

        g.drawString(name, 0, 1260);
        g.drawString(phone, 0, 1290);
        g.drawString(comp, 0, 1320);

        // 关闭画笔
        g.dispose();

        // 生成图片
        File resultImg = new File(outputImgPath + UUID.randomUUID().toString() + ".png");
        ImageIO.write(image, "png", resultImg);

        System.out.println("TestCutImages");

        System.out.println("========== 结束！ ==========");
    }

    /**
     * 计算使用字体的一段字符串的宽
     *
     * @param font
     * @param content
     * @return
     */
    public static int getWordWidth(Font font, String content) {
        FontDesignMetrics metrics = FontDesignMetrics.getMetrics(font);
        int width = 0;
        for (int i = 0; i < content.length(); i++) {
            width += metrics.charWidth(content.charAt(i));
        }
        return width;
    }

    /**
     * 进行裁剪操作
     *
     * @param originalImage the original image
     * @param x             the x
     * @param y             the y
     * @param width         the width
     * @param height        the height
     * @return the buffered image
     * @throws IOException the io exception
     */
    public static BufferedImage cutJPG(BufferedImage originalImage, int x, int y, int width, int height) throws IOException {
        Iterator<ImageReader> iterator = ImageIO.getImageReadersByFormatName("jpg");
        ImageReader reader = iterator.next();
        // 转换成字节流
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ImageIO.write(originalImage, "jpg", outputStream);
        InputStream is = new ByteArrayInputStream(outputStream.toByteArray());

        ImageInputStream iis = ImageIO.createImageInputStream(is);
        reader.setInput(iis, true);
        ImageReadParam param = reader.getDefaultReadParam();
        Rectangle rect = new Rectangle(x, y, width, height);
        param.setSourceRegion(rect);
        BufferedImage bi = reader.read(0, param);
        return bi;
    }

    /**
     * 裁剪图片
     *
     * @param img          the img
     * @param originWidth  the origin width
     * @param originHeight the origin height
     * @return the buffered image
     * @throws Exception the exception
     */
    public static BufferedImage cutPicture(BufferedImage img, int originWidth, int originHeight) throws IOException {
        int width = img.getWidth();  // 原图的宽度
        int height = img.getHeight();  //原图的高度

        int newImage_x = 0; // 要截图的坐标
        int newImage_y = 0; // 要截图的坐标
        if (width > originWidth) {
            newImage_x = (width - originWidth) / 2;
        }
        if (height > originHeight) {
            newImage_y = height - originHeight;
        }
        return cutJPG(img, newImage_x, newImage_y, originWidth, originHeight);
    }

    /**
     * 对头像处理
     *
     * @param image  the image
     * @param radius the radius
     * @return the buffered image
     * @throws Exception the exception
     */
    public static BufferedImage createRoundedImage(String image, int radius) throws Exception {
        BufferedImage img = ImageIO.read(new File(image));
        // 1. 按原比例缩减
        BufferedImage fixedImg = getScaledImage(img, radius, 2);
        // 2. 居中裁剪
        fixedImg = cutPicture(fixedImg, radius, radius);
        // 3. 把正方形生成圆形
        BufferedImage bufferedImage = convertRoundedImage(fixedImg, radius);
        return bufferedImage;
    }

    /**
     * 对头像处理
     *
     * @param img  the image
     * @param radius the radius
     * @return the buffered image
     * @throws Exception the exception
     */
    public static BufferedImage createRoundedBImage(BufferedImage img, int radius) throws Exception {
        // 1. 按原比例缩减
        BufferedImage fixedImg = getScaledImage(img, radius, 2);
        // 2. 居中裁剪
        fixedImg = cutPicture(fixedImg, radius, radius);
        // 3. 把正方形生成圆形
        BufferedImage bufferedImage = convertRoundedImage(fixedImg, radius);
        return bufferedImage;
    }

    /**
     * 方形转为圆形
     *
     * @param img    the img
     * @param radius the radius 半径
     * @return the buffered image
     * @throws Exception the exception
     */
    public static BufferedImage convertRoundedImage(BufferedImage img, int radius) throws IOException {
        BufferedImage result = new BufferedImage(radius, radius, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = result.createGraphics();
        //在适当的位置画图
        g.drawImage(img, (radius - img.getWidth(null)) / 2, (radius - img.getHeight(null)) / 2, null);

        //圆角
        RoundRectangle2D round = new RoundRectangle2D.Double(0, 0, radius, radius, radius * 2, radius * 2);
        Area clear = new Area(new Rectangle(0, 0, radius, radius));
        clear.subtract(new Area(round));
        g.setComposite(AlphaComposite.Clear);

        //抗锯齿
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g.fill(clear);
        g.dispose();

        return result;
    }


    /**
     * 图像等比例缩放
     *
     * @param img     the img
     * @param maxSize the max size
     * @param type    the type
     * @return the scaled image
     */
    public static BufferedImage getScaledImage(BufferedImage img, int maxSize, int type) {
        int w0 = img.getWidth();
        int h0 = img.getHeight();
        int w = w0;
        int h = h0;
        // 头像如果是长方形：
        // 1:高度与宽度的最大值为maxSize进行等比缩放,
        // 2:高度与宽度的最小值为maxSize进行等比缩放
        if (type == 1) {
            w = w0 > h0 ? maxSize : (maxSize * w0 / h0);
            h = w0 > h0 ? (maxSize * h0 / w0) : maxSize;
        } else if (type == 2) {
            w = w0 > h0 ? (maxSize * w0 / h0) : maxSize;
            h = w0 > h0 ? maxSize : (maxSize * h0 / w0);
        }
        Image schedImage = img.getScaledInstance(w, h, Image.SCALE_SMOOTH);
        BufferedImage bufferedImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = bufferedImage.createGraphics();
        g.drawImage(schedImage, 0, 0, null);
        return bufferedImage;
    }

    /**
     * 将图片处理为圆形图片
     * 传入的图片必须是正方形的才会生成圆形 如果是长方形的比例则会变成椭圆的
     *
     * @param url
     * @return
     */
    public static BufferedImage transferImgForRoundImgage(String url) throws IOException {
        BufferedImage resultImg = null;
        if (StringUtils.isBlank(url)) {
            return null;
        }

        BufferedImage buffImg = ImageIO.read(new URL(url));

        resultImg = new BufferedImage(buffImg.getWidth(), buffImg.getHeight(), BufferedImage.TYPE_INT_ARGB);
        // 创建一个椭圆形的2D图像
        Ellipse2D.Double shape = new Ellipse2D.Double(0, 0, buffImg.getWidth(), buffImg.getHeight());
        Graphics2D g = resultImg.createGraphics();
        resultImg = g.getDeviceConfiguration().createCompatibleImage(buffImg.getWidth(), buffImg.getHeight(), Transparency.TRANSLUCENT);
        g = resultImg.createGraphics();
        g.setComposite(AlphaComposite.Clear);
        g.fill(new Rectangle(resultImg.getWidth(), resultImg.getHeight()));
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC, 1.0f));
        // 使用 setRenderingHint 设置抗锯齿
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g.setClip(shape);
        g.drawImage(buffImg, 0, 0, null);
        g.dispose();

        return resultImg;
    }

    public static BufferedImage cutHeadImages1(String headUrl) {
        if (StringUtils.isBlank(headUrl)) {
            return null;
        }

        BufferedImage avatarImage = null;
        try {
            avatarImage = ImageIO.read(new URL(headUrl));
            avatarImage = scaleByPercentage1(avatarImage, avatarImage.getWidth(), avatarImage.getWidth());
            int width = avatarImage.getWidth();
            // 透明底的图片
            BufferedImage formatAvatarImage = new BufferedImage(width, width, BufferedImage.TYPE_4BYTE_ABGR);
            Graphics2D graphics = formatAvatarImage.createGraphics();
            //把图片切成一个园
            graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            //留一个像素的空白区域，这个很重要，画圆的时候把这个覆盖
            int border = 0;
            //图片是一个圆型
            Ellipse2D.Double shape = new Ellipse2D.Double(border, border, width - border * 2, width - border * 2);
            //需要保留的区域
            graphics.setClip(shape);
            graphics.drawImage(avatarImage, border, border, width - border * 2, width - border * 2, null);
            graphics.dispose();
            //在圆图外面再画一个圆
            //新创建一个graphics，这样画的圆不会有锯齿
            graphics = formatAvatarImage.createGraphics();
            graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            int border1 = 0;
            //画笔是4.5个像素，BasicStroke的使用可以查看下面的参考文档
            //使画笔时基本会像外延伸一定像素，具体可以自己使用的时候测试
            Stroke s = new BasicStroke(1F, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
            graphics.setStroke(s);
            graphics.setColor(Color.WHITE);
            graphics.drawOval(border1, border1, width - border1 * 2, width - border1 * 2);
            graphics.dispose();

            return formatAvatarImage;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 缩小Image，此方法返回源图像按给定宽度、高度限制下缩放后的图像
     *
     * @param inputImage ：压缩后宽度
     *                   ：压缩后高度
     * @throws java.io.IOException return
     */
    public static BufferedImage scaleByPercentage1(BufferedImage inputImage, int newWidth, int newHeight) {
        // 获取原始图像透明度类型
        try {
            int type = inputImage.getColorModel().getTransparency();
            int width = inputImage.getWidth();
            int height = inputImage.getHeight();
            // 开启抗锯齿
            RenderingHints renderingHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            // 使用高质量压缩
            renderingHints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            BufferedImage img = new BufferedImage(newWidth, newHeight, type);
            Graphics2D graphics2d = img.createGraphics();
            graphics2d.setRenderingHints(renderingHints);
            graphics2d.drawImage(inputImage, 0, 0, newWidth, newHeight, 0, 0, width, height, null);
            graphics2d.dispose();
            return img;

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
